#pragma once

#include <atomic>

#include <arpa/inet.h>
#include <stddef.h>

#include <boost/intrusive_ptr.hpp>

#include "protocol.h"


/**
 *! @brief 向socket发送指定大小的数据
 * 
 * @param socket   目标套接字
 * @param buffer   数据缓冲区
 * @param length   待发送的数据大小
 * @return int     发送状态(0:成功, errno:失败)
 */
int send_exact(int socket, const void *buffer, size_t length);




/**
 *! @brief 从socket接收指定大小的数据到buffer中
 * 
 * @param socket  从该套接字接收数据
 * @param buffer  接收数据存放的缓冲区
 * @param length  期望接收的数据长度
 * @return int    接收状态(0:成功, errno:失败)
 */
int recv_exact(int socket, void *buffer, size_t length);




// (base) [root@localhost InfiniStore]# show_gids
// DEV       PORT    INDEX   GID                                     IPv4            VER     DEV
// ---       ----    -----   ---                                     ------------    ---     ---
// rocep0s6   1       0    fe80:0000:0000:0000:9e63:c0ff:fe5c:517c                    v1    ens6np0
// rocep0s6   1       1    fe80:0000:0000:0000:9e63:c0ff:fe5c:517c                    v2    ens6np0
// rocep0s6   1       2    0000:0000:0000:0000:0000:ffff:c0a8:640a 192.168.100.10     v1    ens6np0
// rocep0s6   1       3    0000:0000:0000:0000:0000:ffff:c0a8:640a 192.168.100.10     v2    ens6np0

/**
 *! @brief 将RDMA网卡的GID转换为人类可读的字符串
 * 
 * @param gid     RDMA网卡的GID
 * @return std::string   人类可读的GID字符串表示形式
 */
std::string human_readable_gid(union ibv_gid gid);



/**
 *! @brief 打印RDMA连接信息
 * 
 * @param info  RDMA连接信息
 * @param is_remote 是否为远程RDMA连接
 */
void print_rdma_conn_info(rdma_conn_info_t *info, 
                        bool is_remote);




/**
 *! @brief 异常中端信号堆栈信息打印
 * 
 * @param signum 信号
 */
void signal_handler(int signum);




/**
 *! @brief 答应向量信息(用于调试)
 * 
 * @tparam T 
 * @param ptr 
 * @param size 
 */
template <typename T>
void print_vector(T *ptr, size_t size);



//! IntrusivePtr 对象基类, 用于使用智能指针管理内存回收
//! intrusive_ptr直接利用类内部的引用计数，无需像shared_ptr那样额外分配内存

// 使用方式: boost::intrusive_ptr<IntrusivePtrTarget> p(new IntrusivePtrTarget)
// p会根据引用计数自动释放
class IntrusivePtrTarget {
public:
    IntrusivePtrTarget() : ref_count(0) {}

    virtual ~IntrusivePtrTarget() = default;


    // 禁用拷贝和赋值构造函数
    IntrusivePtrTarget(const IntrusivePtrTarget &) = delete;
    IntrusivePtrTarget &operator=(const IntrusivePtrTarget &) = delete;



    // 友元函数(可以访问累的私有成员ref_count)
    //! intrusive_ptr 必须实现该函数, 用于引用计数和对象销毁
    friend void intrusive_ptr_add_ref(IntrusivePtrTarget *p) {
        p->ref_count.fetch_add(1, std::memory_order_relaxed);
    }


    // 友元函数(可以访问累的私有成员ref_count)
    //! intrusive_ptr 必须实现该函数, 用于引用计数和对象销毁
    friend void intrusive_ptr_release(IntrusivePtrTarget *p) {
        if (p->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
            delete p;
        }
    }

private:
    // 用 mutable 豁免 const 限制
    mutable std::atomic<int> ref_count;
};

